package cn.bugstack.ai.test.spring.ai;

import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.api.Advisor;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.MetadataMode;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
import org.springframework.ai.ollama.OllamaEmbeddingModel;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.ai.ollama.api.OllamaOptions;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.OpenAiEmbeddingOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.reader.TextReader;
import org.springframework.ai.retry.RetryUtils;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.FileSystemResource;
import org.springframework.test.context.junit4.SpringRunner;

import javax.sql.DataSource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * AutoAgent 工作流 + RAG (检索增强生成) 测试类
 *
 * 作用: 演示如何将 RAG 技术集成到 AutoAgent 工作流中
 * 触发条件: 用户询问需要依赖本地知识库的问题
 * 数据流向:
 * 1. 文档加载 → 向量化 → 存储到 PGVector
 * 2. 用户提问 → 向量检索 → 增强 Prompt → LLM 生成答案
 *
 * RAG 核心流程:
 * 加载文档 → 文本分块 → Embedding 向量化 → 向量数据库存储 → 语义检索 → 上下文增强 → LLM 生成
 *
 * 测试方法:
 * 1. test_rag_simple() - 基础 RAG 测试(加载文档 → 检索 → 生成)
 * 2. test_rag_with_mcp() - RAG + MCP 工具(检索增强 + 工具调用)
 * 3. test_rag_multi_docs() - 多文档 RAG(批量加载、混合检索)
 */
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class AutoAgentWorkflowWithRagTest {

        @Value("${spring.ai.openai.base-url}")
        private String openaiBaseUrl;

        @Value("${spring.ai.openai.api-key}")
        private String openaiApiKey;

        /** PGVector 数据源(从 Spring 容器注入) */
        @Autowired
        @Qualifier("pgVectorDataSource")
        private DataSource pgVectorDataSource;

        /** Chat 模型 */
        private ChatModel chatModel;

        /** Embedding 模型(用于向量化) */
        private EmbeddingModel embeddingModel;

        /** 向量数据库 */
        private VectorStore vectorStore;

        /** 知识库目录 */
        private static final String KNOWLEDGE_DIR = "E:\\cursor\\ai-agent-station-study\\docs";

        /**
         * 初始化 RAG 环境
         */
        @Before
        public void init() {
                log.info("\n╔══════════════════════════════════════════════════════════════════════════════╗");
                log.info("║                     初始化 RAG 测试环境                                       ║");
                log.info("╚══════════════════════════════════════════════════════════════════════════════╝");

                // ========== 1. 初始化 Chat 模型 ==========
                log.info("\n[1/3] 初始化 Chat 模型...");
                OpenAiApi openAiApi = OpenAiApi.builder()
                                .baseUrl(openaiBaseUrl)
                                .apiKey(openaiApiKey)
                                .completionsPath("v1/chat/completions")
                                .embeddingsPath("v1/embeddings")
                                .build();

                this.chatModel = OpenAiChatModel.builder()
                                .openAiApi(openAiApi)
                                .defaultOptions(OpenAiChatOptions.builder()
                                                .model("deepseek-chat")
                                                .maxTokens(2000)
                                                .temperature(0.3) // 降低温度以提高准确性
                                                .toolCallbacks(Collections.emptyList())
                                                .build())
                                .build();
                log.info("✅ Chat 模型初始化完成 (Model: deepseek-chat)");

                // ========== 2. 初始化 Embedding 模型 ==========
                log.info("\n[2/3] 初始化 Embedding 模型...");

                // ========== 混合配置: Chat(DeepSeek) + Embedding(Ollama) ==========
                // 使用 Ollama 本地模型处理向量化,免费且快速
                OllamaApi ollamaApi = OllamaApi.builder()
                                .baseUrl("http://localhost:11434")
                                .build();

                // 使用 builder 模式创建 OllamaEmbeddingModel
                this.embeddingModel = OllamaEmbeddingModel.builder()
                                .ollamaApi(ollamaApi)
                                .defaultOptions(OllamaOptions.builder()
                                                .model("nomic-embed-text")  // Ollama embedding 模型
                                                .build())
                                .build();
                log.info("✅ Embedding 模型初始化完成 (Provider: Ollama, Model: nomic-embed-text)");

                // ========== 备选方案: 智谱 AI (余额充足后可切换) ==========
                /*
                // 智谱 AI Embeddings API 配置
                OpenAiApi zhipuEmbeddingApi = OpenAiApi.builder()
                                .baseUrl("https://open.bigmodel.cn/api/paas/v4")
                                .apiKey("a2eb28611f3c4d1bb9df7dba8e50cf58.z68MbWUKgke4IAXY")
                                .embeddingsPath("/embeddings")
                                .build();

                this.embeddingModel = new OpenAiEmbeddingModel(
                                zhipuEmbeddingApi,
                                MetadataMode.EMBED,
                                OpenAiEmbeddingOptions.builder()
                                                .model("embedding-2")  // 或 embedding-3
                                                .build(),
                                RetryUtils.DEFAULT_RETRY_TEMPLATE
                );
                log.info("✅ Embedding 模型初始化完成 (Provider: 智谱 AI, Model: embedding-2)");
                */

                // ========== 3. 初始化 PGVector 向量数据库 ==========
                log.info("\n[3/3] 初始化 PGVector 向量数据库...");
                try {
                        org.springframework.jdbc.core.JdbcTemplate jdbcTemplate = new org.springframework.jdbc.core.JdbcTemplate(
                                        pgVectorDataSource);

                        // ========== 手动确保 PGVector 扩展和表结构 ==========
                        log.info("   - 检查并安装 pgvector 扩展...");
                        try {
                                jdbcTemplate.execute("CREATE EXTENSION IF NOT EXISTS vector");
                                log.info("   ✅ pgvector 扩展已就绪");
                        } catch (Exception e) {
                                log.warn("   ⚠️ pgvector 扩展可能已存在: {}", e.getMessage());
                        }

                        // 删除旧表（如果存在）
                        log.info("   - 清理旧测试表...");
                        jdbcTemplate.execute("DROP TABLE IF EXISTS public.vector_store_test");

                        // 手动创建表结构
                        log.info("   - 创建新测试表...");
                        jdbcTemplate.execute(
                                        "CREATE TABLE public.vector_store_test (" +
                                                        "id UUID PRIMARY KEY DEFAULT gen_random_uuid(), " +
                                                        "content TEXT NOT NULL, " +
                                                        "metadata JSONB, " +
                                                        "embedding vector(768)" +  // Ollama nomic-embed-text 维度
                                                        ")");
                        log.info("   ✅ 测试表创建成功");

                        // ========== 初始化 PgVectorStore ==========
                        this.vectorStore = PgVectorStore.builder(jdbcTemplate, embeddingModel)
                                        .vectorTableName("vector_store_test")  // 测试专用表
                                        .dimensions(768)  // Ollama nomic-embed-text 维度为 768
                                        .distanceType(PgVectorStore.PgDistanceType.COSINE_DISTANCE) // 余弦距离
                                        .removeExistingVectorStoreTable(false) // 已手动创建，不再自动删除
                                        .initializeSchema(false) // 已手动创建，不再自动初始化
                                        .build();

                        log.info("✅ PGVector 向量数据库初始化完成");
                        log.info("   - 表名: vector_store_test (测试专用)");
                        log.info("   - 向量维度: 768 (Ollama nomic-embed-text)");
                        log.info("   - 距离算法: COSINE_DISTANCE (余弦相似度)");
                        log.info("   - 表结构: 已手动创建");
                } catch (Exception e) {
                        log.error("❌ PGVector 初始化失败", e);
                        throw new RuntimeException("PGVector 初始化失败: " + e.getMessage(), e);
                }

                log.info("\n╔══════════════════════════════════════════════════════════════════════════════╗");
                log.info("║                     RAG 测试环境初始化完成 ✅                                  ║");
                log.info("╚══════════════════════════════════════════════════════════════════════════════╝");
        }

        // ========== 辅助方法 ==========

        /**
         * 加载文档并向量化存储
         *
         * @param filePath 文档路径
         * @return 文档数量
         */
        private int loadAndVectorizeDocument(String filePath) throws IOException, InterruptedException {
                log.info("\n📄 正在加载文档: {}", filePath);

                // 1. 读取文档
                TextReader textReader = new TextReader(new FileSystemResource(filePath));
                List<Document> documents = textReader.get();
                log.info("✅ 文档读取成功,原始文档数: {}", documents.size());

                // 2. 文本分块(避免超出 Token 限制)
                TokenTextSplitter textSplitter = new TokenTextSplitter(
                                500, // 每块最大 Token 数
                                100, // 块之间重叠 Token 数(保证上下文连贯性)
                                5, // 最小块大小
                                10000, // 最大块大小
                                true // 保留分隔符
                );
                List<Document> splitDocuments = textSplitter.apply(documents);
                log.info("✅ 文档分块完成,分块数: {} (每块 ~500 tokens)", splitDocuments.size());

                // 3. 向量化并存储到 PGVector (分批插入，避免单次数据包过大)
                log.info("🔄 开始向量化并存储...");
                long startTime = System.currentTimeMillis();

                // 分批插入，每批10个文档块
                int batchSize = 10;
                int totalBatches = (int) Math.ceil((double) splitDocuments.size() / batchSize);
                log.info("   - 总文档块数: {}", splitDocuments.size());
                log.info("   - 批次大小: {} 块/批", batchSize);
                log.info("   - 总批次数: {}", totalBatches);

                for (int i = 0; i < splitDocuments.size(); i += batchSize) {
                        int end = Math.min(i + batchSize, splitDocuments.size());
                        List<Document> batch = splitDocuments.subList(i, end);
                        int currentBatch = (i / batchSize) + 1;

                        log.info("   [批次 {}/{}] 插入 {} 个文档块...", currentBatch, totalBatches, batch.size());
                        try {
                                vectorStore.add(batch);
                        } catch (Exception e) {
                                log.warn("   ⚠️ 批次 {} 插入失败，重试中...", currentBatch);
                                // 重试一次
                                Thread.sleep(2000);
                                vectorStore.add(batch);
                        }
                }

                long costTime = System.currentTimeMillis() - startTime;
                log.info("✅ 向量化存储完成,耗时: {} ms ({:.2f} 秒)", costTime, costTime / 1000.0);

                return splitDocuments.size();
        }

        /**
         * 批量加载文档
         *
         * @param directoryPath 文档目录
         * @param filePattern   文件匹配模式(如 "*.md", "*.txt")
         * @return 总文档块数
         */
        private int loadDocumentsFromDirectory(String directoryPath, String filePattern) throws IOException {
                log.info("\n📂 正在扫描目录: {}", directoryPath);
                log.info("   文件模式: {}", filePattern);

                List<Path> files = Files.walk(Paths.get(directoryPath))
                                .filter(Files::isRegularFile)
                                .filter(p -> p.toString().matches(filePattern.replace("*", ".*")))
                                .collect(Collectors.toList());

                log.info("✅ 找到 {} 个匹配文件", files.size());

                int totalChunks = 0;
                for (Path file : files) {
                        try {
                                int chunks = loadAndVectorizeDocument(file.toString());
                                totalChunks += chunks;
                        } catch (Exception e) {
                                log.warn("⚠️ 跳过文件 {}: {}", file.getFileName(), e.getMessage());
                        }
                }

                log.info("\n📊 批量加载完成:");
                log.info("   - 文件数: {}", files.size());
                log.info("   - 总文档块数: {}", totalChunks);

                return totalChunks;
        }

        // ========== 测试方法 ==========

        /**
         * 测试1: 基础 RAG 工作流
         *
         * 流程:
         * 1. 加载文档到向量库
         * 2. 用户提问
         * 3. 向量检索相关内容
         * 4. 使用 QuestionAnswerAdvisor 增强 Prompt
         * 5. LLM 生成答案
         */
        @Test
        public void test_rag_simple() {
                log.info("\n" +
                                "╔═══════════════════════════════════════════════════════════════╗\n" +
                                "║                  RAG 基础工作流测试                            ║\n" +
                                "╚═══════════════════════════════════════════════════════════════╝");

                try {
                        // ========== 阶段1: 加载文档 ==========
                        log.info("\n╭─────────────────────────────────────────────────────────────────────────────╮");
                        log.info("│  📚 阶段1: 加载知识库文档                                                    │");
                        log.info("╰─────────────────────────────────────────────────────────────────────────────╯");

                        // 假设我们有一个测试文档
                        String testDocPath = KNOWLEDGE_DIR + "\\AI-Agent-MCP-RAG学习计划.md";
                        int docChunks = loadAndVectorizeDocument(testDocPath);
                        log.info("\n✅ 知识库准备完成,共 {} 个文档块", docChunks);

                        // ========== 阶段2: RAG 问答 ==========
                        log.info("\n╭─────────────────────────────────────────────────────────────────────────────╮");
                        log.info("│  🤖 阶段2: RAG 检索增强问答                                                  │");
                        log.info("╰─────────────────────────────────────────────────────────────────────────────╯");

                        // 创建带 RAG 增强的 ChatClient
                        ChatClient ragChatClient = ChatClient.builder(chatModel)
                                        .defaultSystem("你是一个基于知识库的智能助手。" +
                                                        "你必须根据提供的上下文(Context)来回答问题。" +
                                                        "如果上下文中没有相关信息,请明确告知用户。" +
                                                        "回答要准确、简洁,并引用上下文中的关键信息。")
                                        .defaultAdvisors(
                                                        new QuestionAnswerAdvisor(vectorStore))
                                        .build();

                        // 用户提问
                        String userQuestion = "MCP 是什么?它的核心作用是什么?";
                        log.info("\n👤 用户提问: {}", userQuestion);

                        log.info("\n🔄 RAG 工作流开始:");
                        log.info("   [1/3] 向量检索相关文档...");
                        log.info("   [2/3] 构建增强 Prompt...");
                        log.info("   [3/3] LLM 生成答案...");

                        long startTime = System.currentTimeMillis();
                        String answer = ragChatClient
                                        .prompt(userQuestion)
                                        .call()
                                        .content();
                        long costTime = System.currentTimeMillis() - startTime;

                        log.info("\n✅ RAG 回答完成 (耗时: {} ms / {:.2f} 秒)", costTime, costTime / 1000.0);
                        log.info("\n🤖 AI 回答:");
                        log.info("┌─────────────────────────────────────────────────────────────────────────────┐");
                        for (String line : answer.split("\n")) {
                                if (!line.trim().isEmpty()) {
                                        log.info("│ {}", line);
                                }
                        }
                        log.info("└─────────────────────────────────────────────────────────────────────────────┘");

                        // ========== 阶段3: 验证检索效果 ==========
                        log.info("\n╭─────────────────────────────────────────────────────────────────────────────╮");
                        log.info("│  🔍 阶段3: 验证向量检索效果                                                  │");
                        log.info("╰─────────────────────────────────────────────────────────────────────────────╯");

                        // 手动执行向量检索,查看相似度
                        List<Document> similarDocs = vectorStore.similaritySearch(
                                        org.springframework.ai.vectorstore.SearchRequest.builder().query(userQuestion).topK(3).build() // 取相似度最高的 3 个文档块
                        );

                        log.info("\n📊 检索到 {} 个相关文档块:", similarDocs.size());
                        for (int i = 0; i < similarDocs.size(); i++) {
                                Document doc = similarDocs.get(i);
                                log.info("\n[文档块 {}/{}]", i + 1, similarDocs.size());
                                log.info("内容预览: {}",
                                                doc.getText().length() > 150
                                                                ? doc.getText().substring(0, 150) + "..."
                                                                : doc.getText());
                        }

                        log.info("\n✅ RAG 基础测试成功!");

                } catch (Exception e) {
                        log.error("\n❌ 测试失败: {}", e.getMessage(), e);
                        throw new RuntimeException(e);
                }
        }

        /**
         * 测试2: RAG + MCP 工具(检索增强 + 工具调用)
         *
         * 场景: 既需要查询知识库,又需要调用外部工具(如文件系统、搜索)
         * 优势: 结合本地知识和实时工具能力
         */
        @Test
        public void test_rag_with_mcp() {
                log.info("\n" +
                                "╔═══════════════════════════════════════════════════════════════╗\n" +
                                "║              RAG + MCP 工具集成测试                            ║\n" +
                                "╚══════════════���════════════════════════════════════════════════╝");

                try {
                        // ========== 阶段1: 初始化知识库 ==========
                        log.info("\n╭─────────────────────────────────────────────────────────────────────────────╮");
                        log.info("│  📚 阶段1: 初始化知识库                                                      │");
                        log.info("╰─────────────────────────────────────────────────────────────────────────────╯");

                        String testDocPath = KNOWLEDGE_DIR + "\\AI-Agent-MCP-RAG学习计划.md";
                        int docChunks = loadAndVectorizeDocument(testDocPath);
                        log.info("✅ 知识库加载完成,共 {} 个文档块", docChunks);

                        // ========== 阶段2: 初始化 MCP 工具 ==========
                        log.info("\n╭─────────────────────────────────────────────────────────────────────────────╮");
                        log.info("│  🔧 阶段2: 初始化 MCP 工具                                                   │");
                        log.info("╰─────────────────────────────────────────────────────────────────────────────╯");

                        // 初始化文件系统 MCP
                        McpSyncClient fsClient = createFilesystemMcpClient();
                        SyncMcpToolCallbackProvider toolCallbackProvider = new SyncMcpToolCallbackProvider(fsClient);
                        log.info("✅ 文件系统 MCP 初始化成功");

                        // ========== 阶段3: RAG + MCP 混合问答 ==========
                        log.info("\n╭─────────────────────────────────────────────────────────────────────────────╮");
                        log.info("│  🤖 阶段3: RAG + MCP 混合问答                                                │");
                        log.info("╰─────────────────────────────────────────────────────────────────────────────╯");

                        // 创建同时支持 RAG 和 MCP 的 ChatClient
                        ChatClient hybridChatClient = ChatClient.builder(chatModel)
                                        .defaultSystem("你是一个强大的智能助手。" +
                                                        "你可以:\n" +
                                                        "1. 查询知识库(RAG)获取专业知识\n" +
                                                        "2. 使用文件系统工具查看项目文件\n" +
                                                        "你应该结合这两种能力来回答用户问题。")
                                        .defaultAdvisors(
                                                        new QuestionAnswerAdvisor(vectorStore))
                                        .defaultOptions(OpenAiChatOptions.builder()
                                                        .model("deepseek-chat")
                                                        .maxTokens(3000)
                                                        .temperature(0.3)
                                                        .toolCallbacks(toolCallbackProvider.getToolCallbacks())
                                                        .build())
                                        .build();

                        // 用户提问(需要同时用到知识库和文件系统)
                        String userQuestion = "根据学习计划,MCP 相关的测试文件在哪些目录?请列出实际文件路径。";
                        log.info("\n👤 用户提问: {}", userQuestion);

                        log.info("\n🔄 混合工作流开始:");
                        log.info("   [1/4] 向量检索知识库(RAG)...");
                        log.info("   [2/4] 调用文件系统工具(MCP)...");
                        log.info("   [3/4] 整合检索和工具结果...");
                        log.info("   [4/4] LLM 生成综合答案...");

                        long startTime = System.currentTimeMillis();
                        String answer = hybridChatClient
                                        .prompt(userQuestion)
                                        .call()
                                        .content();
                        long costTime = System.currentTimeMillis() - startTime;

                        log.info("\n✅ 混合问答完成 (耗时: {} ms / {:.2f} 秒)", costTime, costTime / 1000.0);
                        log.info("\n🤖 AI 回答:");
                        log.info("┌─────────────────────────────────────────────────────────────────────────────┐");
                        for (String line : answer.split("\n")) {
                                if (!line.trim().isEmpty()) {
                                        log.info("│ {}", line);
                                }
                        }
                        log.info("└─────────────────────────────────────────────────────────────────────────────┘");

                        log.info("\n✅ RAG + MCP 混合测试成功!");

                } catch (Exception e) {
                        log.error("\n❌ 测试失败: {}", e.getMessage(), e);
                        throw new RuntimeException(e);
                }
        }

        /**
         * 测试3: 多文档 RAG(批量加载)
         *
         * 场景: 加载整个目录的文档,构建完整知识库
         */
        @Test
        public void test_rag_multi_docs() {
                log.info("\n" +
                                "╔═══════════════════════════════════════════════════════════════╗\n" +
                                "║                  多文档 RAG 测试                               ║\n" +
                                "╚═══════════════════════════════════════════════════════════════╝");

                try {
                        // ========== 阶段1: 批量加载文档 ==========
                        log.info("\n╭─────────────────────────────────────────────────────────────────────────────╮");
                        log.info("│  📚 阶段1: 批量加载 docs 目录所有 Markdown 文件                             │");
                        log.info("╰─────────────────────────────────────────────────────────────────────────────╯");

                        long loadStartTime = System.currentTimeMillis();
                        int totalChunks = loadDocumentsFromDirectory(KNOWLEDGE_DIR, ".*\\.md");
                        long loadCostTime = System.currentTimeMillis() - loadStartTime;

                        log.info("\n✅ 知识库构建完成");
                        log.info("   - 总文档块数: {}", totalChunks);
                        log.info("   - 耗时: {} ms ({:.2f} 秒)", loadCostTime, loadCostTime / 1000.0);

                        // ========== 阶段2: 多轮问答 ==========
                        log.info("\n╭─────────────────────────────────────────────────────────────────────────────╮");
                        log.info("│  🤖 阶段2: 多轮 RAG 问答                                                     │");
                        log.info("╰─────────────────────────────────────────────────────────────────────────────╯");

                        ChatClient ragChatClient = ChatClient.builder(chatModel)
                                        .defaultSystem("你是基于项目知识库的智能助手。" +
                                                        "请根据上下文准确回答问题,并说明信息来源。")
                                        .defaultAdvisors(
                                                        new QuestionAnswerAdvisor(vectorStore) // QuestionAnswerAdvisor 使用默认配置
                                        )
                                        .build();

                        // 问题1
                        String question1 = "项目的学习计划包含哪些主题?";
                        log.info("\n[问题 1] {}", question1);
                        String answer1 = ragChatClient.prompt(question1).call().content();
                        log.info("[回答 1] {}", answer1.length() > 200 ? answer1.substring(0, 200) + "..." : answer1);

                        // 问题2
                        String question2 = "什么是 DDD 架构?";
                        log.info("\n[问题 2] {}", question2);
                        String answer2 = ragChatClient.prompt(question2).call().content();
                        log.info("[回答 2] {}", answer2.length() > 200 ? answer2.substring(0, 200) + "..." : answer2);

                        // 问题3
                        String question3 = "项目使用的核心技术栈是什么?";
                        log.info("\n[问题 3] {}", question3);
                        String answer3 = ragChatClient.prompt(question3).call().content();
                        log.info("[回答 3] {}", answer3.length() > 200 ? answer3.substring(0, 200) + "..." : answer3);

                        log.info("\n✅ 多文档 RAG 测试成功!");

                } catch (Exception e) {
                        log.error("\n❌ 测试失败: {}", e.getMessage(), e);
                        throw new RuntimeException(e);
                }
        }

        // ========== 辅助方法: MCP 客户端创建 ==========

        /**
         * 创建文件系统 MCP 客户端
         */
        private McpSyncClient createFilesystemMcpClient() {
                log.info("初始化文件系统 MCP 客户端...");

                String npxPath = System.getProperty("os.name").toLowerCase().contains("win")
                                ? "npx.cmd"
                                : "npx";

                var stdioParams = ServerParameters.builder(npxPath)
                                .args("-y", "@modelcontextprotocol/server-filesystem",
                                                "E:\\\\cursor\\\\ai-agent-station-study")
                                .build();

                var mcpClient = McpClient.sync(new StdioClientTransport(stdioParams))
                                .requestTimeout(Duration.ofMinutes(3))
                                .build();

                try {
                        mcpClient.initialize();
                        log.info("✅ 文件系统 MCP 初始化成功");
                        return mcpClient;
                } catch (Exception e) {
                        log.error("❌ 文件系统 MCP 初始化失败", e);
                        throw new RuntimeException("MCP 客户端初始化失败: " + e.getMessage(), e);
                }
        }
}